import functools

# 高阶函数除了可以接受函数作为参数外，还可以把函数作为结果值返回。
# 这样调用的时候 才会真正执行

def add(*args):
    def calc():
        s=0;
        for i in args:
            s=s+i
        return s
    return calc

print(add(1,2,3,4,5))

print(add(1,2,3,4,5)())

# 注意到返回的函数在其定义内部引用了局部变量args，所以，当一个函数返回了一个函数后，
# 其内部的局部变量还被新函数引用，所以，闭包用起来简单，实现起来可不容易。
# 返回闭包时牢记一点：返回函数不要引用任何循环变量，或者后续会发生变化的变量。


#匿名函数
print(list(map(lambda x,y:x*x+y*y,[1,2,3],[1,2,3])))

power_m=lambda x:x*x
print(power_m(5))

#装饰器 Decorator
# 在函数调用前后自动打印日志，但又不希望修改now()函数的定义，
# 这种在代码运行期间动态增加功能的方式，称之为“装饰器”（Decorator）。

def now():
    print('2018-01-10')

#现在要在 不改变now函数的前提下 给其添加执行前日志
def log(func):
    def wrapper(*args,**kwargs):
        print('call %s():'%func.__name__)
        return func(*args,**kwargs)
    return wrapper

@log  #now1=log(now1)
def now1():
    print('2018-01-10')

now1()

#如果log 要传入参数

def log_a(text):
    def log(func):
        def wrapper(*args, **kwargs):
            print('%s %s():' % (text,func.__name__))
            return func(*args, **kwargs)
        return wrapper
    return log


@log_a('excute')  #now2=log_a(text)(now2)
def now2():
    print('2018-01-10')

now2()

print(now2.__name__)

#防止__name__ 被改变 使用@functools.wraps(func)

def log_a_w(text):
    def log(func):
        @functools.wraps(func)
        def wrapper(*args,**kwargs):
            print('%s %s():'%(text,func.__name__))
            return func(*args,**kwargs)
        return wrapper
    return log

@log_a_w('excute')  #now3=log_a(text)(now3)
def now3():
    print('2018-01-10')

print(now3.__name__)

